`include "define.v"
/*
	Control and Status Registers
    
*/

module csrs
(  
    input   wire 	            clk,
	input   wire 	            rstn,
	input	wire	[31:00]		instr,
    input   wire    [63:00]     pc,
	input	wire			    bubble_flag,
    input	wire	[11:00]	    csr_id,
    input   wire                csr_write_back_en,
    input   wire    [11:00]     csr_write_back_id,
    input	wire   	[63:00]     csr_write_back_data,
    //
    input   wire                mei_flag,
    input   wire                msi_flag,
    input   wire                mti_flag,
    input   wire                irq_flag,

    input   wire                instr_addr_misalig,
    input   wire                instr_acc_fault,
    input   wire                illegal_instr,    
    input   wire                ebreak,           
    input   wire                load_addr_misalig,
    input   wire                load_acc_fault,
    input   wire                store_addr_misalig,
    input   wire                store_acc_fault,
    input   wire                ecall,  
    input   wire                mret,
    input   wire                exc_flag,
    //
    output  reg     [63:00]     mstatus,
    output  reg     [63:00]     mie,

    output  reg     [63:00]     mtvec,
    //
    output	reg     [63:00]     mepc,
    output	reg   	[63:00]     csr_output
);
    //
    reg     [63:00]         mtval;
    wire    [63:00]         mip; 
    reg     [63:00]         mscratch;
    reg     [63:00]         mcause;         
    // 机器信息
    reg		[63:00]	        mvendorid;
    reg		[63:00]	        marchid;
    reg		[63:00]	        mimpid;
    reg		[63:00]	        mhartid; 
    reg		[63:00]	        misa;
    // Machine counter
    reg		[63:00]	        mcycle;
    reg 	[63:00] 	    minstret;



    
//-----------------------------------------------------------------------------------------------------
    // Machine information
    always @(posedge clk) begin
        if( !rstn ) begin
            mvendorid                           <= 64'b0;
            marchid                             <= 64'b0;
            mimpid                              <= 64'b0;
            mhartid                             <= 64'b0;
        end
    end
// ----------------------------------------------Machine trap setup----------------------------------------------
    // mstatus
    always @(posedge clk) begin
        if  ( !rstn )                                             mstatus         <=  64'h0000_1800;   // MPP�[12:11])中内容永远为1
        else begin
            if      ( exc_flag     ) begin
                `MPIE       <= `MIE;
                `MIE        <= 1'b0;
            end
            else if ( mret )    begin
                `MIE        <= `MPIE;
                `MPIE       <= 1'b1;
            end
            else if( csr_write_back_en && csr_write_back_id == 12'h300 )   mstatus         <=  csr_write_back_data;
            else                                                mstatus         <=  mstatus;
        end
    end
    // misa
    always @(posedge clk) begin
        if  ( !rstn )                                             misa            <=  64'h80000_0100;   
    end
    // mie
    always @(posedge clk) begin
        if  ( !rstn )                                             mie             <=  64'd0;           // 
        else    begin
            if( csr_write_back_en && csr_write_back_id == 12'h304 )                mie             <=  csr_write_back_data;
        end
    end
    // mtvec
    always @(posedge clk) begin
        if  ( !rstn )                                             mtvec           <=  64'b0;
        else    begin
            if( csr_write_back_en && csr_write_back_id == 12'h305 )        mtvec           <=  csr_write_back_data;
        end
    end
// -----------------------------------Machine trap handling-----------------------------------
    // mscratch
    always @(posedge clk) begin
        if  ( !rstn )                                             mscratch        <=  64'b0;
        else begin
            if      ( csr_write_back_en && csr_write_back_id == 12'h340 )  mscratch        <=  csr_write_back_data;
            else                                                mscratch        <=  mscratch;
        end 
    end
    // mepc
    always @(posedge clk) begin
        if  ( !rstn )                                             mepc          <=  64'b0;
        else begin
            if      ( exc_flag )                                mepc          <=  pc;
            else if ( irq_flag )                                mepc          <=  pc;
            else if ( csr_write_back_en && csr_write_back_id == 12'h341 )          mepc          <=  csr_write_back_data;
            else                                                mepc          <=  mepc;
        end 
    end
    // mcause
    always @(posedge clk) begin
        if  ( !rstn )                                             mcause            <=  64'b0;
        else begin
            if      ( instr_addr_misalig            )           mcause            <=  64'h0000_0000_0000_0000;
            else if ( instr_acc_fault               )           mcause            <=  64'h0000_0000_0000_0001;
            else if ( illegal_instr                 )           mcause            <=  64'h0000_0000_0000_0002;
            else if ( ebreak                        )           mcause            <=  64'h0000_0000_0000_0003;
            else if ( load_addr_misalig             )           mcause            <=  64'h0000_0000_0000_0004;
            else if ( load_acc_fault                )           mcause            <=  64'h0000_0000_0000_0005;
            else if ( store_addr_misalig            )           mcause            <=  64'h0000_0000_0000_0006;
            else if ( store_acc_fault               )           mcause            <=  64'h0000_0000_0000_0007;
            else if ( ecall                         )           mcause            <=  64'h0000_0000_0000_000B;
            else if ( mei_flag                      )           mcause            <=  64'h8000_0000_0000_000B;
            else if ( msi_flag                      )           mcause            <=  64'h8000_0000_0000_0003;
            else if ( mti_flag                      )           mcause            <=  64'h8000_0000_0000_0007;
            else                                                mcause            <=  mcause;
        end
    end


    // mtval
    always @(posedge clk) begin
        if  ( !rstn )                                             mtval            <=  64'b0;
        else begin
            if      ( instr_addr_misalig            )           mtval            <=  instr;
            else if ( load_acc_fault                )           mtval            <=  pc;
            else if ( illegal_instr                 )           mtval            <=  instr;
            else if ( ebreak                        )           mtval            <=  instr;
            else if ( load_addr_misalig             )           mtval            <=  instr;
            else if ( load_acc_fault                )           mtval            <=  pc;
            else if ( store_addr_misalig            )           mtval            <=  instr;
            else if ( store_acc_fault               )           mtval            <=  pc;
            else if ( ecall                         )           mtval            <=  instr;
            else                                                mtval            <=  mtval;
        end
    end
    // mip
    /*
        assign  `MEIP    =   mei;
        assign  `MSIP    =   msi;
        assign  `MTIP    =   mti;
    */

    assign  mip = {52'b0,mei_flag,3'b0,mti_flag,3'b0,msi_flag,3'b0};
    
//-------------------------Machine counters------------------------------------
    
	always @(posedge clk) begin
        if  ( !rstn ) begin	 
            mcycle                              <= 64'b0;                   // 
            minstret                            <= 64'b0;                   // 
		end
        else begin
            mcycle                              <= mcycle + 1;								            
            minstret	                        <= bubble_flag ? minstret : minstret + 1;
        end
	end


    // output
    always @( * ) begin
        case (csr_id) 
            12'hF11     :   csr_output =    mvendorid;          //  Vendor ID.
            12'hF12     :   csr_output =    marchid;            //  Architecture ID.
            12'hF13     :   csr_output =    mimpid;             //  Implementation ID.
            12'hF14     :   csr_output =    mhartid;            //  Hardware thread ID.
            12'h301     :   csr_output =    misa;               //  ISA and extensions
            12'h300     :   csr_output =    mstatus ;
            12'h304     :   csr_output =    mie     ;
            12'h305     :   csr_output =    mtvec   ;
            12'h340     :   csr_output =    mscratch;
            12'h341     :   csr_output =    mepc    ;
            12'h342     :   csr_output =    mcause  ;
            12'h343     :   csr_output =    mtval   ;
            12'h344     :   csr_output =    mip;                   //MIP
            12'hB00     :   csr_output =    mcycle  ;
            12'hB02     :   csr_output =    minstret;
            default     :   csr_output =    64'b0;
        endcase        
    end


 
endmodule   
